package com.luych.toolbox.gateway.center.controller;

import com.luych.toolbox.common.feign.intf.base.service.LetterFeign;
import com.luych.toolbox.common.feign.intf.gateway.center.WebSocketFeign;
import com.luych.toolbox.common.feign.param.base.service.LetterParam;
import com.luych.toolbox.common.feign.param.gateway.center.WebSocketChat;
import com.luych.toolbox.common.feign.param.gateway.center.WebSocketLetter;
import com.luych.toolbox.common.feign.param.gateway.center.WebSocketNotice;
import com.luych.toolbox.common.feign.param.gateway.center.WebSocketTask;
import com.luych.toolbox.common.feign.view.gateway.center.WebSocketSession;
import com.luych.toolbox.gateway.center.exception.WebSocketNotFoundException;
import com.luych.toolbox.gateway.center.websocket.WebSocketCache;
import com.luych.toolbox.gateway.center.websocket.WebSocketEndPoint;
import com.luych.toolbox.gateway.center.websocket.WebSocketMessage;
import io.swagger.annotations.Api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.websocket.CloseReason;
import javax.websocket.Session;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Api(tags = "WebSocket消息管理")
@RestController
@RequestMapping("/api/websocket")
public class WebSocketController implements WebSocketFeign {

    private static final Logger logger = LoggerFactory.getLogger(WebSocketController.class);

    private final WebSocketEndPoint webSocketEndPoint;
    private final LetterFeign letterFeign;

    @Autowired
    public WebSocketController(WebSocketEndPoint webSocketEndPoint, LetterFeign letterFeign) {
        this.webSocketEndPoint = webSocketEndPoint;
        this.letterFeign = letterFeign;
    }

    @Override
    public List<WebSocketSession> get() {
        return WebSocketCache.getSessions().entrySet().stream()
                .map(entry -> {
                    WebSocketSession session = new WebSocketSession();
                    session.setUserId(entry.getKey());
                    session.setSessionId(entry.getValue().getId());
                    return session;
                }).collect(Collectors.toList());
    }

    private ResponseEntity<?> webSocket(String userId, WebSocketMessage webSocketMessage) {
        try {
            webSocketEndPoint.onSend(userId, webSocketMessage);
            return new ResponseEntity<>(HttpStatus.NO_CONTENT);
        } catch (WebSocketNotFoundException e) {
            return new ResponseEntity<>(e.getMessage(), HttpStatus.NOT_FOUND);
        } catch (IOException e) {
            return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    @Override
    public ResponseEntity<?> notice(String userId, WebSocketNotice webSocketNotice) {
        return this.webSocket(userId, new WebSocketMessage(webSocketNotice));
    }

    @Override
    public ResponseEntity<?> letter(String userId, WebSocketLetter webSocketLetter) {
        if (StringUtils.isEmpty(webSocketLetter.getId())) {
            webSocketLetter.setId(UUID.randomUUID().toString());
        }

        LetterParam letter = new LetterParam();
        letter.setId(webSocketLetter.getId());
        letter.setUserId(userId);
        letter.setType(webSocketLetter.getType());
        letter.setMessage(webSocketLetter.getMessage());
        letter.setContent(webSocketLetter.getContent());
        letterFeign.create(letter);
        
        return this.webSocket(userId, new WebSocketMessage(webSocketLetter));
    }

    @Override
    public ResponseEntity<?> task(String userId, WebSocketTask webSocketTask) {
        return this.webSocket(userId, new WebSocketMessage(webSocketTask));
    }

    @Override
    public ResponseEntity<?> chat(String userId, WebSocketChat webSocketChat) {
        return this.webSocket(userId, new WebSocketMessage(webSocketChat));
    }

    @Override
    public ResponseEntity<?> close(String userId) {
        Session session = WebSocketCache.get(userId);
        if (session == null) return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        try {
            session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "User logout"));
            logger.info("Close websocket success, userId: {}", userId);
            return new ResponseEntity<>(HttpStatus.NO_CONTENT);
        } catch (IOException e) {
            logger.error("Close websocket error, userId: {}, message: {}", userId, e.getMessage(), e);
            return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}
